use serde_json::json;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::pubkey::Pubkey;
use solana_transaction_status::{
    UiParsedMessage, UiTransactionStatusMeta, UiTransactionTokenBalance,
};
use std::str::FromStr;

fn get_token(meta: &UiTransactionStatusMeta) -> Option<&UiTransactionTokenBalance> {
    if let Some(pre_token_balances) = &meta.pre_token_balances {
        if !pre_token_balances.is_empty() {
            Some(&pre_token_balances[0])
        } else {
            None
        }
    } else if let Some(post_token_balances) = &meta.post_token_balances {
        if !post_token_balances.is_empty() {
            Some(&post_token_balances[0])
        } else {
            None
        }
    } else {
        None
    }
}

fn get_price(meta: &UiTransactionStatusMeta) -> String {
    meta.log_messages
        .as_ref()
        .unwrap()
        .iter()
        .find(|msg| msg.contains("\"price\""))
        .unwrap_or(&"0".to_string())
        .replace("Program log: {\"price\":", "")
        .replace(",\"seller_expiry\":-1}", "")
}

pub async fn process_magiceden(
    _rpc_client: &RpcClient,
    signature: &str,
    message: &UiParsedMessage,
    meta: &UiTransactionStatusMeta,
) -> Option<serde_json::Value> {
    let signer = message.account_keys.iter().find(|account| account.signer);
    let signer = match signer {
        Some(signer) => signer,
        None => return None,
    };

    let token = match get_token(meta) {
        Some(mint) => mint,
        None => return None,
    };

    let mint = &token.mint;

    let token: Option<String> = Pubkey::try_find_program_address(
        &[
            &Pubkey::from_str(&signer.pubkey).unwrap().to_bytes(),
            &Pubkey::from_str("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
                .unwrap()
                .to_bytes(),
            &Pubkey::from_str(mint).unwrap().to_bytes(),
        ],
        &Pubkey::from_str("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL").unwrap(),
    )
    .map(|token| token.0.to_string());

    let price = get_price(meta);

    Some(json!({
        "marketplace": "magiceden",
        "signer": signer.pubkey,
        "mint": mint,
        "signature": signature.to_string(),
        "price": price,
        "id": token,
        "auction_house": "E8cU1WiRWjanGxmn96ewBgk9vPTcL6AEZ1t6F6fkgUWe",
    }))
}
